<?php

/***

LZRoster: A roster for World of Warcraft.
Copyright (C) 2007  Emmanuel Cron

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

***/

require_once dirname(__FILE__)."/Sql.class.php";
require_once dirname(__FILE__)."/Config.class.php";
require_once dirname(__FILE__)."/Localization.class.php";
require_once dirname(__FILE__)."/StatusRoster.class.php";
require_once dirname(__FILE__)."/SessionRoster.class.php";

class FileImporter
{
	private $upload_data;
	private $num_items_deleted = 0;
	private $num_spells_deleted = 0;
	private $num_items_updated = 0;
	private $num_spells_updated = 0;
	private $num_crafts_updated = array();
	private $num_reagents_updated = array();
	private $num_old_custom_ids_updated = 0;
	private $num_dungeons_updated = array();
	private $num_specializations_updated = array();
	private $account_owns_character = null;
	
	static private $acc_own_not_created = 1;
	static private $acc_own_own = 2;
	static private $acc_own_no_own = 3;
	
	function FileImporter(&$file) {
		$this->upload_data = $file;
	}
	
	function Import()
	{
		$return_code = "OK\n\n";
	    
		// Check if data format is valid
	    if (
			!array_key_exists('Items', $this->upload_data)
			or
			!array_key_exists('Spells', $this->upload_data)
			or
			!array_key_exists('Characters', $this->upload_data)
			or
			!array_key_exists('Revision', $this->upload_data)
			or
			!array_key_exists('Locale', $this->upload_data)
		) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('your file is not well formed, cannot continue'));
			return "200";
		}
		
		// Check if data is not too old
		if ( $this->upload_data['Revision'] < 97 or $this->upload_data['Revision'] >= 40000 ) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('your version of LZProfiler is no more supported, please update your addon'));
			return "201";
		}
		
		// Delete old items with their id
		if ($this->DeleteOldItems() != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not delete old items for update'));
			return "202";
		} else {
			StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('deleted %s old items', $this->GetNumItemsDeleted()));
			$return_code .= "IT_DEL:" . $this->GetNumItemsDeleted() . "\n";
		}
		
		// Add new items
		if ($this->ImportNewItems() != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not import your collected items'));
			return "203";
		} else {
			StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('updated %s items in the database', $this->GetNumItemsUpdated()));
			$return_code .= "IT_UPD:" . $this->GetNumItemsUpdated() . "\n";
		}
		
		// Delete old spells with their id
		if ($this->DeleteOldSpells() != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not delete old spells for update'));
			return "204";
		} else {
			StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('deleted %s old spells', $this->GetNumSpellsDeleted()));
			$return_code .= "SP_DEL:" . $this->GetNumSpellsDeleted() . "\n";
		}
		
		// Add new spells
		if ($this->ImportNewSpells() != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not import your collected spells in the database'));
			return "205";
		} else {
			StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('updated %s spells in the database', $this->GetNumSpellsUpdated()));
			$return_code .= "SP_UPD:" . $this->GetNumSpellsUpdated() . "\n";
		}
		
		StatusRoster::GetInstance()->AddBlank();
		StatusRoster::GetInstance()->AddNote(Localization::GetInstance()->Get('now importing characters that are on %s server and in one of these guilds %t', Config::GetInstance()->GetRosterServer(), implode(", ", Config::GetInstance()->GetRosterGuilds())));
		StatusRoster::GetInstance()->AddBlank();
		
		// Import all characters
		foreach ($this->GetDataCharacters() as $character_name)
		{
			$return_code .= "\n";
		    
		    StatusRoster::GetInstance()->AddNote(Localization::GetInstance()->Get('importing data for %s', $character_name));
			$return_code .= "CH_NAME:" . $character_name . "\n";
			
			if ( $this->IsInAuthorizedGuild($character_name) == false ) {
				// Character not in authorized guild
				
				StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('this character is not member of an authorized guild'));
				$return_code .= "CH_INV_GUILD\n";
			} elseif ($this->AccountOwnsCharacter($character_name) == self::$acc_own_no_own) {
				// Character not owned by current account
				
				StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('this character is not owned by your account'));
				$return_code .= "CH_NOT_OWNED\n";
			} else {
				// Character can be imported
				
				if ( $this->ImportCharacter($character_name) == false) {
					// Could not import
					
					StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('update of character failed'));
					$return_code .= "CH_UP_FAIL\n";
				} else {
					// Character successfully imported
					
					StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('character successfully updated'));
					$return_code .= "CH_UP_OK\n";
					
					// Deletes old crafts based on unique ids of crafts to update
					if ( $this->DeleteOldCrafts($character_name) == false ) {
						StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not delete old professions'));
						$return_code .= "CH_PR_DL_FAIL\n";
					} else {
						StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('deletion of old professions successful'));
						$return_code .= "CH_PR_DL_OK\n";
						
						// Import new crafts
						if ( $this->ImportNewCrafts($character_name) == true ) {
							StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('updated %s crafts and %t reagents', $this->GetNumCraftsUpdated($character_name), $this->GetNumReagentsUpdated($character_name)));
							$return_code .= "CH_CR_UP:" . $this->GetNumCraftsUpdated($character_name) . "\n";
							$return_code .= "CH_RG_UP:" . $this->GetNumReagentsUpdated($character_name) . "\n";
						}
					}
					
					// Update unique ids that have changed
					if ( $this->UpdateOldCustomIds() == false) {
						StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not upgrade old crafts to new ones'));
						$return_code .= "{TODO}";
					}
					
					StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('upgraded %s old crafts to new ones', $this->num_old_custom_ids_updated));
					
					// Import dungeons access
					if ( $this->ImportDungeons($character_name) == false ) {
						StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('update of dungeon access failed'));
						$return_code .= "CH_DG_UP_FAIL\n";
					} else {
						StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('updated %s dungeon access', $this->GetNumDungeonsUpdated($character_name)));
						$return_code .= "CH_DG_UP:" . $this->GetNumDungeonsUpdated($character_name) . "\n";
					}
					
					// Import specializations
					if ( $this->ImportSpecializations($character_name) == false ) {
						StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('update of craft specializations failed'));
						$return_code .= "CH_SP_UP_FAIL\n";
					} else {
						StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('updated %s craft specializations', $this->GetNumSpecializationsUpdated($character_name)));
						$return_code .= "CH_SP_UP:" . $this->GetNumSpecializationsUpdated($character_name) . "\n";
					}
				}
				
			}
			
			StatusRoster::GetInstance()->AddBlank();
		}
		
		$return_code .= "\n";
		
		// Update statistics
		if ( $this->UpdateStatistics() == false ) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not update the statistics of your account'));
			$return_code .= "ST_UP_FAIL\n";
		} else {
			StatusRoster::GetInstance()->AddSuccess(Localization::GetInstance()->Get('statistics of your account updated successfully'));
			$return_code .= "ST_UP_OK\n";
		}
		
		StatusRoster::GetInstance()->AddBlank();
		StatusRoster::GetInstance()->AddNote(Localization::GetInstance()->Get('end of process'));
		
		return $return_code;
	}
	
	private function UpdateStatistics()
	{
		if (Sql::GetInstance()->Query("
			UPDATE
				`cp_accounts`
			SET
				`account_times_uploaded` = `account_times_uploaded`+1,
				`account_nb_items_updated` = `account_nb_items_updated`+".$this->GetNumItemsUpdated().",
				`account_nb_spells_updated` = `account_nb_spells_updated`+".$this->GetNumSpellsUpdated().",
				`account_nb_reagents_updated` = `account_nb_reagents_updated`+".$this->GetNumReagentsUpdated().",
				`account_last_upload` = NOW()
			WHERE
				`account_id`='".SessionRoster::GetInstance()->GetAccountId()."'
		") != true)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	
	private function AccountOwnsCharacter($character_name)
	{
		if ( $this->account_owns_character == null)
		{
			$this->account_owns_character = array();
			
			Sql::GetInstance()->Query("
				SELECT
					`character_account_id`,
					`Name`
				FROM
					`cp_characters`
				WHERE
					`Name` IN ('".implode("', '", $this->GetDataCharacters())."')
			");
			
			while ( $v = Sql::GetInstance()->IterateResults() )
			{
				$this->account_owns_character[$v['Name']] = $v['character_account_id'];
			}
		}
		
		if ( !array_key_exists($character_name, $this->account_owns_character) )
		{
			return self::$acc_own_not_created;
		}
		elseif ( $this->account_owns_character[$character_name] == SessionRoster::GetInstance()->GetAccountId() )
		{
			return self::$acc_own_own;
		}
		else
		{
			return self::$acc_own_no_own;
		}
	}
	
	private function DeleteOldItems()
	{
		if ( count($this->upload_data['Items']) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			DELETE FROM
				`cp_items`
			WHERE
				`Revision` < '".$this->GetDataRevision()."'
			AND
				`Locale`='".$this->GetDataLocale()."'
			AND
				`ItemId` IN ('".implode("', '", $this->GetNewItemsIds())."')
		") != true) {
			return false;
		} else
		{
			$this->num_items_deleted = $this->num_items_deleted + Sql::GetInstance()->GetResultsNumber();
			
			return true;
		}
	}
	
	private function ImportNewCrafts($character_name)
	{
		// Don't update if nothing to update
		if ( count($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Professions']) < 1 ) {
			return true;
		}
		
		// Store in $professions and $reagents
		// the new reagents and professions
		$this->GetProfessionsData_Sql($character_name, $professions, $reagents);
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_reagents`
			
				(
				`reagent_profession_custom_id`,
				`Revision`,
				`ItemId`,
				`ItemQuantity`
				)
			VALUES
				".$reagents."
		") != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not update all reagents'));
			
			return false;
		}
		
		$this->num_reagents_updated[$character_name] = Sql::GetInstance()->GetResultsNumber();
		
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_professions`
			
				(
				`profession_custom_id`,
				`Locale`,
				`CharacterName`,
				`ProfessionName`,
				`CategoryName`,
				`CraftName`,
				`ItemId`,
				`SpellId`
				)
			VALUES
				".$professions."
		") != true) {
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('could not update all crafts'));
			
			return false;
		}
		
		$this->num_crafts_updated[$character_name] = Sql::GetInstance()->GetResultsNumber();
		
		return true;
	}
	
	private function GetNumReagentsUpdated($character_name = null)
	{
		if ($character_name == null)
		{
			$t_reagents = 0;
			
			foreach($this->num_reagents_updated as $v)
			{
				$t_reagents = $t_reagents + $v;
			}
			
			return $t_reagents;
		}
		
		if ( array_key_exists($character_name, $this->num_reagents_updated) )
		{
			return $this->num_reagents_updated[$character_name];
		}
		else
		{
			return 0;
		}
	}
	
	private function GetNumCraftsUpdated($character_name)
	{
		if ( array_key_exists($character_name, $this->num_crafts_updated) )
		{
			return $this->num_crafts_updated[$character_name];
		}
		else
		{
			return 0;
		}
	}
	
	private function ImportNewItems()
	{
		if ( count( $this->upload_data['Items'] ) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_items`
			
				(
				`Revision`,
				`Locale`,
				`ItemId`,
				`Name`,
				`Color`,
				`Texture`
				)
			VALUES
				".$this->GetObjectData_Sql('Items')."
		") != true)
		{
			return false;
		}
		else
		{
			$this->num_items_updated = $this->num_items_updated + Sql::GetInstance()->GetResultsNumber();
			return true;
		}
	}
	
	private function GetNewItemsIds()
	{
		$table = array();
		
		foreach ($this->upload_data['Items'] as $k => $v)
		{
			array_push($table, $k);
		}
		
		return $table;
	}
	
	private function DeleteOldSpells()
	{
		if ( count($this->upload_data['Spells']) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			DELETE FROM
				`cp_spells`
			WHERE
				`Revision` < '".$this->GetDataRevision()."'
			AND
				`Locale`='".$this->GetDataLocale()."'
			AND
				`SpellId` IN ('".implode("', '", $this->GetNewSpellsIds())."')
		") != true)
		{
			return false;
		}
		else
		{
			$this->num_spells_deleted = $this->num_spells_deleted + Sql::GetInstance()->GetResultsNumber();
			
			return true;
		}
	}
	
	private function ImportNewSpells()
	{
		if ( count( $this->upload_data['Spells'] ) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_spells`
			
				(
				`Revision`,
				`Locale`,
				`SpellId`,
				`Name`,
				`Color`,
				`Texture`
				)
			VALUES
				".$this->GetObjectData_Sql('Spells')."
		") != true)
		{
			return false;
		}
		else
		{
			$this->num_spells_updated = $this->num_spells_updated + Sql::GetInstance()->GetResultsNumber();
			return true;
		}
	}
	
	private function ImportDungeons($character_name)
	{
		if ( count($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Dungeons']) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_dungeons`
			
				(
				`CharacterName`,
				`Dungeon`
				)
			VALUES
				".$this->GetDungeonData_Sql($character_name)."
		") != true)
		{
			return false;
		}
		else
		{
			$this->num_dungeons_updated[$character_name] = Sql::GetInstance()->GetResultsNumber();
			
			return true;
		}
	}
	
	private function ImportSpecializations($character_name)
	{
		if ( count($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Specializations']) < 1 )
		{
			return true;
		}
		
		if (Sql::GetInstance()->Query("
			INSERT IGNORE INTO
				`cp_specializations`
			
				(
				`CharacterName`,
				`Specialization`
				)
			VALUES
				".$this->GetSpecializationData_Sql($character_name)."
		") != true)
		{
			return false;
		}
		else
		{
			$this->num_specializations_updated[$character_name] = Sql::GetInstance()->GetResultsNumber();
			
			return true;
		}
	}
	
	private function ImportCharacter($character_name)
	{
		$word = null;
		$where = null;
		
		if ( $this->AccountOwnsCharacter($character_name) == self::$acc_own_not_created )
		{
			$word = "INSERT INTO";
		}
		else
		{
			$word = "UPDATE";
			$where = "WHERE `Name` = '".$character_name."'";
		}
		
		$root = $this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name];
		
		if (Sql::GetInstance()->Query("
			".$word."
				`cp_characters`
			SET
				`character_account_id` = '".SessionRoster::GetInstance()->GetAccountId()."',
				`Revision` = '".$this->GetDataRevision()."',
				`Locale` = '".$this->GetDataLocale()."',
				`Name` = '".$character_name."',
				`FactionEn` = '".$root['FactionEn']."',
				`RaceEn` = '".$root['RaceEn']."',
				`ClassEn` = '".$root['ClassEn']."',
				`SexId` = '".$root['SexId']."',
				`Level` = '".$root['Level']."',
				`CurrentExperience` = '".$root['CurrentExperience']."',
				`MaxExperience` = '".$root['MaxExperience']."',
				`RestedExperience` = ".( array_key_exists('RestedExperience', $root) ? "'".$root['RestedExperience']."'" : "NULL" ).",
				`GuildTitle` = ".( array_key_exists('Guild', $root) ? "'".$root['Guild']['Title']."'" : "NULL" ).",
				`GuildRank` = ".( array_key_exists('Guild', $root) ? "'".$root['Guild']['Rank']."'" : "NULL" ).",
				`TimePlayed` = '".$root['TimePlayed']."',
				`TimeLevelPlayed` = '".$root['TimeLevelPlayed']."',
				`timestampUpdate` = '".$root['timestampUpdate']."'
			".$where."
		") != true) {
			return false;
		} else {
			return true;
		}
	}
	
	private function GetDungeonData_Sql($character_name)
	{
		$string = null;
		
		foreach ($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Dungeons'] as $k => $v)
		{
			$string .= "(";
			$string .= "'".$character_name."'";
			$string .= ",";
			$string .= "'".$k."'";
			$string .= ")";
			$string .= ",";
		}
		
		$string = substr($string, 0, strlen($string)-1);
		
		return $string;
	}
	
	private function GetSpecializationData_Sql($character_name)
	{
		$string = null;
		
		foreach ($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Specializations'] as $k => $v)
		{
			$string .= "(";
			$string .= "'".$character_name."'";
			$string .= ",";
			$string .= "'".$k."'";
			$string .= ")";
			$string .= ",";
		}
		
		$string = substr($string, 0, strlen($string)-1);
		
		return $string;
	}
	
	private function GetProfessionsData_Sql($character_name, &$string_professions, &$string_reagents)
	{
		foreach ($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Professions'] as $profession_name => $profession)
		{
			foreach ($profession as $category_name => $category)
			{
				foreach ($category as $item_name => $item_data)
				{
					$t_custom_id = $this->CreateCustomId($item_data); // Cache to avoid too much processing
					
					$string_professions .= $this->GetCraftData_Sql(
						$t_custom_id,
						$item_data,
						$character_name,
						$profession_name,
						$category_name,
						$item_name
					);
					
					if ( count($item_data['Reagents']) > 0 )
					{
						foreach ($item_data['Reagents'] as $reagent_id => $reagent_data)
						{
							$string_reagents .= $this->GetReagentData_Sql($t_custom_id, $reagent_id, $reagent_data);
						}
					}
				}
			}
		}
		
		$string_professions = substr($string_professions, 0, strlen($string_professions)-1);
		$string_reagents = substr($string_reagents, 0, strlen($string_reagents)-1);
	}
	
	private function GetReagentData_Sql($t_custom_id, $reagent_id, $reagent_data)
	{
		$string = null;
		
		$string .= "(";
		$string .= "'".$t_custom_id."'";
		$string .= ",";
		$string .= "'".$this->GetDataRevision()."'";
		$string .= ",";
		$string .= "'".$reagent_id."'";
		$string .= ",";
		$string .= "'".$reagent_data['Quantity']."'";
		$string .= ")";
		$string .= ",";
		
		return $string;
	}
	
	private function GetCraftData_Sql($t_custom_id, $craft_data, $character_name, $profession, $category, $craft_name)
	{
		$string = null;
		
		$string .= "( '".$t_custom_id."',";
		$string .= "'".$this->GetDataLocale()."',";
		$string .= "'".$character_name."',";
		$string .= "'".$profession."',";
		$string .= "'".$category."',";
		$string .= "'".$craft_name."',";
		$string .= "'".( array_key_exists('Item', $craft_data) ? $craft_data['Item'] : null )."',";
		$string .= "'".( array_key_exists('Spell', $craft_data) ? $craft_data['Spell'] : null )."')";
		$string .= ",";
		
		return $string;
	}
	
	private function GetObjectData_Sql($key)
	{
		$string = null;
		
		foreach ($this->upload_data[$key] as $k => $v)
		{
			$string .= "('".$this->GetDataRevision()."',";
			$string .= "'".$this->GetDataLocale()."',";
			$string .= "'".$k."',";
			$string .= "'".$v['RealName']."',";
			$string .= "'".$v['Color']."',";
			$string .= "'".$v['Texture']."')";
			$string .= ",";
		}
		
		$string = substr($string, 0, strlen($string)-1);
		
		return $string;
	}
	
	private function UpdateOldCustomIds() {
		$toChange = array();
	
		if (Sql::GetInstance()->Query("
			SELECT
				COUNT( DISTINCT `profession_custom_id` ) AS count,
				GROUP_CONCAT( `profession_custom_id` ORDER BY `profession_id` SEPARATOR '$' ) AS customIds,
				GROUP_CONCAT( `profession_id` ORDER BY `profession_id` SEPARATOR '$' ) AS ids,
				`CraftName`
			FROM `cp_professions`
			GROUP BY `ProfessionName` , `CategoryName` , `CraftName`
			HAVING count > 1
		") != true) {
			return false;
		}
		
		// Get duplicate custom ids for a single craft
		while ($result = Sql::GetInstance()->IterateResults()) {
			// Get the custom ids in an array
			$customIds = explode("$", $result['customIds']);
			
			// Get the newest id
			$newId = $customIds[count($customIds)-1];
			
			$ids = explode("$", $result['ids']);
			foreach($customIds as $customId) {
				// Find the ids to change
				if ($customId != $newId) {
					// Store it
					$toChange[$customId] = $newId;
				}
			}
		}
		
		$this->num_old_custom_ids_updated = Sql::GetInstance()->GetResultsNumber();

		// Return if nothing to update
		if ($this->num_old_custom_ids_updated == 0) {
			return true;
		}
		
		// Update old craft ids
		foreach($toChange as $oldId => $newId) {
			Sql::GetInstance()->Query("
				UPDATE IGNORE `cp_professions`
				SET `profession_custom_id`='".$newId."'
				WHERE `profession_custom_id`='".$oldId."'
			");
		}
		
		// Delete crafts from old ids
		if (Sql::GetInstance()->Query("
			DELETE FROM `cp_professions`
			WHERE `profession_custom_id` IN ('".implode("','", array_keys($toChange))."')
		") != true) {
			return false;
		}
		
		// Delete reagents from old ids
		if (Sql::GetInstance()->Query("
			DELETE FROM `cp_reagents`
			WHERE `reagent_profession_custom_id` IN ('".implode("','", array_keys($toChange))."')
		") != true) {
			return false;
		}
		
		return true;
	}
	
	private function DeleteOldCrafts($character_name)
	{
		// Don't do anything if no professions to update
		if ( count($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Professions']) < 1 ) {
			return true;
		}
		
		
		$t_new_professions_ids = $this->GetNewProfessionsIds($character_name); // Cache to avoid too much processing
		
		if (Sql::GetInstance()->Query("
			DELETE FROM
				`cp_professions`
			WHERE
				`CharacterName`='".$character_name."'
			AND
				`profession_custom_id` IN ('".implode("','", $t_new_professions_ids)."')
		") != true) {
			return false;
		}
		
		if (Sql::GetInstance()->Query("
			DELETE FROM
				`cp_reagents`
			WHERE
				`Revision` < '".$this->GetDataRevision()."'
			AND
				`reagent_profession_custom_id` IN ('".implode("','", $t_new_professions_ids)."')
		") != true)
		{
			return false;
		}
		
		return true;
	}
	
	/**
	 * Returns an array containing an unique id for
	 * each craft contained in the uploaded file
	 * for the given character.
	 * 
	 * @param $character_name the name of the character
	 * 		to retrieve the craft's unique ids in
	 * 		the file
	 * @return an array unique craft ids
	 */
	private function GetNewProfessionsIds($character_name) {
		$table = array();
		
		foreach ($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name]['Professions'] as $profession) {
			// For each profession contained in file
			
			foreach ($profession as $category) {
				// For each category in profession
				
				foreach ($category as $item_data) {
					// Add all unique ids to the table to return
					 
					array_push($table, $this->CreateCustomId($item_data));
				}
			}
		}
		
		return $table;
	}
	
	private function CreateCustomId($object)
	{
		$custom_id = null;
		
		if ( array_key_exists('Item', $object) )
		{
			$custom_id .= "i".$object['Item'];
		}
		else
		{
			$custom_id .= "s".$object['Spell'];
		}
		
		if ( array_key_exists('Reagents', $object) and count($object['Reagents'] > 0) )
		{
			ksort($object['Reagents']);
			
			$custom_id .= ":";
			
			foreach ($object['Reagents'] as $k => $v)
			{
				$custom_id .= $k;
				$custom_id .= ",";
				$custom_id .= $v['Quantity'];
				$custom_id .= ":";
			}
			
			$custom_id = substr($custom_id, 0, strlen($custom_id)-1);
		}
		
		return $custom_id;
	}
	
	private function GetNewSpellsIds()
	{
		$table = array();
		
		foreach ($this->upload_data['Spells'] as $k => $v)
		{
			array_push($table, $k);
		}
		
		return $table;
	}
	
	private function GetDataRevision()
	{
		return $this->upload_data['Revision'];
	}
	
	private function GetDataLocale()
	{
		return $this->upload_data['Locale'];
	}
	
	private function GetNumItemsUpdated()
	{
		return $this->num_items_updated;
	}
	
	private function GetNumSpellsUpdated()
	{
		return $this->num_spells_updated;
	}
	
	private function GetNumSpellsDeleted()
	{
		return $this->num_spells_deleted;
	}
	
	private function GetNumItemsDeleted()
	{
		return $this->num_items_deleted;
	}
	
	private function GetNumDungeonsUpdated($character_name)
	{
		if ( array_key_exists($character_name, $this->num_dungeons_updated) )
		{
			return $this->num_dungeons_updated[$character_name];
		}
		else
		{
			return 0;
		}
	}
	
	private function GetNumSpecializationsUpdated($character_name)
	{
		if ( array_key_exists($character_name, $this->num_specializations_updated) )
		{
			return $this->num_specializations_updated[$character_name];
		}
		else
		{
			return 0;
		}
	}
	
	private function IsInAuthorizedGuild($character_name)
	{
		$root = $this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()][$character_name];
		
		if ( !array_key_exists('Guild', $root) )
		{
			return false;
		}
		
		foreach (Config::GetInstance()->GetRosterGuildsRawWithSlashes() as $guild_name)
		{
			if ( $root['Guild']['Name'] == $guild_name )
			{
				return true;
			}
		}
		
		return false;
	}
	
	private function GetDataCharacters()
	{
		if ( array_key_exists( Config::GetInstance()->GetRosterServerRawWithSlashes(), $this->upload_data['Characters'] ) )
		{
			return array_keys($this->upload_data['Characters'][Config::GetInstance()->GetRosterServerRawWithSlashes()]);
		}
		else
		{
			StatusRoster::GetInstance()->AddError(Localization::GetInstance()->Get('no character found on this server'));
			StatusRoster::GetInstance()->AddBlank();
			
			return array();
		}
	}
}

?>
